/**
 * @file tuya_sdk_callback.c
 * @brief Common process - adapter the flash api
 * @version 0.1
 * @date 2021-11-10
 *
 * @copyright Copyright 2020-2021 Tuya Inc. All Rights Reserved.
 *
 */
#include <string.h>
#include "tkl_memory.h"

#include "tkl_endpoint_register.h"
#include "tal_log.h"
#include "tal_sleep.h"
#include "tal_system.h"
#include "tal_memory.h"
#include "tal_sw_timer.h"
#include "tal_zcl_scene.h"
#include "tal_network_mgr.h"
#include "tal_data_receive.h"
#include "tal_reset_factory.h"
#include "tal_heartbeat.h"
#include "tal_mf_test.h"
#include "tal_attribute_rw.h"

#include "app_common.h"
#include "app_dev_register.h"

#include "tuya_sdk_callback.h"
#include "tal_zigbee_local_init.h"

#include "bsp.h"

#if APP_KEY_SUPPORT
#include "app_key.h"
#endif
#if APP_LED_SUPPORT
#include "app_led.h"
#endif
#if APP_GPIO_SUPPORT
#include "app_gpio.h"
#endif



// app event and handler
TIMER_ID      etimer_preheat_event_id;
TIMER_ID      etimer_network_up_delay_event_id;

extern BOOL_T sys_init_finish_flag;

STATIC VOID_T app_preheat_event_handler(TIMER_ID timer_id, VOID_T *arg);
STATIC VOID_T app_network_up_delay_event_handler(TIMER_ID timer_id, VOID_T *arg);

// app event create
//  STATIC VOID_T app_event_init(VOID_T);
// debug uart init
STATIC VOID_T app_debug_uart_init(VOID_T);
// oem init
// STATIC VOID_T app_oem_init(VOID_T);

#if ENABLE_TAL_LOG
#ifndef MCU_CORE_8258
/**
 * @brief
 *
 * @param str
 * @return VOID_T
 */

#endif
#endif
/**
 * @description: app preheat and network up delay event create
 * @param[in] none
 * @return: none
 */
VOID_T app_event_init(VOID_T)
{
  tal_sw_timer_create(app_preheat_event_handler, NULL, &etimer_preheat_event_id);
  tal_sw_timer_create(app_network_up_delay_event_handler, NULL, &etimer_network_up_delay_event_id);
}

/**
 * @description: preheat event handler
 * @param [in] timer_id: timer id
 * @param[in] args: null
 * @return: none
 */
STATIC VOID_T app_preheat_event_handler(TIMER_ID timer_id, VOID_T *arg)
{
#if APP_LED_SUPPORT
  app_led_preheat_init();
#endif
}

/**
 * @description: network up delay event
 * @param [in] timer_id: timer id
 * @param[in] args: null
 * @return: none
 */
STATIC VOID_T app_network_up_delay_event_handler(TIMER_ID timer_id, VOID_T *arg)
{
  UINT8_T i;
  for (i = 0; i < CHANNEL_NUM; i++)
  {
    if ((device_status.relStatus & (1 << i)))
      app_onoff_cluster_read_report(i + 1);
    else
      app_onoff_cluster_read_report(i + 1);
  }
  TAL_PR_TRACE("start report full\r\n");
}
/**
 * @brief [TUYA_WEAK_ATTRIBUTE function],set device version according to ep_id
 *
 * @param[in] ep_id
 * @return TKL_DEV_VER_T
 */
TKL_DEV_VER_E tkl_zg_endpoint_to_device_version(UINT8_T ep_id)
{
  return (TKL_DEV_VER_E)0xa0;
}

/**
 * @brief pre-sleep callback
 */
STATIC VOID_T app_pre_sleep_cb(VOID_T)
{
  // TAL_PR_TRACE("app_pre_sleep_cb\r\n");
}

/**
 * @brief post-wakeup callback
 */
STATIC VOID_T app_post_wakeup_cb(VOID_T)
{
  // TAL_PR_TRACE("app_post_wakeup_cb\r\n");
}
/**
 * @description: oem init
 * @param [in] none
 * @return: none
 */
VOID_T app_oem_init(VOID_T)
{
  key_config_t key_info[] = APP_KEY_CONFIG_DEFAULT;
  app_key_oem_init(key_info);

  app_led_oem_init();


}
STATIC VOID_T app_uart_output(IN CONST CHAR_T *str)
{
  tal_uart_write(USER_UART, str, strlen(str));
}
/**
 * @brief Generally used for peripheral initialization
 *
 * @return OPERATE_RET
 */
OPERATE_RET tuya_init_first(VOID_T)
{
  app_debug_uart_init();

#if ENABLE_TAL_LOG
#ifdef MCU_CORE_8258
  tal_log_create_manage_and_init(TAL_LOG_LEVEL_TRACE, 128, app_uart_output); //(CONST TAL_LOG_OUTPUT_CB)Tl_printf);
#else
  tal_log_create_manage_and_init(TAL_LOG_LEVEL_TRACE, 128, app_uart_output);
#endif
#endif

  tal_mf_test_disable_beacon_test();
  // tal_zigbee_local_auto_func_enable();
  TAL_PR_DEBUG("/*********first init*********,reason=%d/\r\n", tal_system_get_reset_reason(NULL));
  return OPRT_OK;
}

/**
 * @brief Generally used for register zigbee device
 *
 * @return OPERATE_RET
 */
OPERATE_RET tuya_init_second(VOID_T)
{
  dev_zigbee_init();

  // UINT8_T attr = 0x02;
  // OPERATE_RET ret = tal_zg_write_attribute(0x01,
  //                                          CLUSTER_IAS_ZONE_CLUSTER_ID,
  //                                          ATTR_ZONE_ID_ATTRIBUTE_ID,
  //                                          &attr,
  //                                          ATTR_INT8U_ATTRIBUTE_TYPE);
  // TAL_PR_TRACE("attr[%d], status[%d]\r\n", attr, ret);

  // attr = 0;
  // ret = tal_zg_read_attribute(0x01,
  //                             CLUSTER_IAS_ZONE_CLUSTER_ID,
  //                             ATTR_ZONE_ID_ATTRIBUTE_ID,
  //                             (VOID_T *)&attr,
  //                             1);
  // all_update_data();
  // TAL_PR_TRACE("attr[%d], status[%d]\r\n", attr, ret);

  TAL_PR_TRACE("/*********1.0.0 second init*********/\r\n");
  return OPRT_OK;
}

/**
 * @brief Generally used for initialization before manufacturing test
 *
 * @return OPERATE_RET
 */
OPERATE_RET tuya_init_third(VOID_T)
{
  TAL_PR_TRACE("/*********third init*********/\r\n");
  return OPRT_OK;
}

/**
 * @brief Generally used for initialization after manufacturing test
 *
 * @return OPERATE_RET
 */
OPERATE_RET tuya_init_last(VOID_T)
{
  sys_init_finish_flag = TRUE;
  app_oem_init();
  app_event_init();
#if USE_SLEEP
  tal_sw_timer_start(etimer_preheat_event_id, 100, TAL_TIMER_ONCE);
  TUYA_SLEEP_CB_T v_cb = {app_pre_sleep_cb, app_post_wakeup_cb};
  tal_cpu_sleep_callback_register(&v_cb);
#endif
  tal_uart_deinit(USER_UART);
  app_debug_uart_init();

  device_init();

  TAL_PR_TRACE("/*********last init*********/\r\n");
  return OPRT_OK;
}

/**
 * @brief user-defined callback interface in main loop.do not block!!!
 *
 * @return OPERATE_RET
 */
OPERATE_RET tuya_main_loop(VOID_T)
{
  return OPRT_OK;
}

VOID_T tal_zg_ota_start_callback(UINT_T image_size, VOID_T *argv)
{
  tuya_zg_poll_interval_set(200);
  tal_zg_poll_forever_with_param();
}

VOID_T tal_zg_ota_end_callback(UINT8_T result)
{
  tuya_zg_poll_interval_set(1000);
  tal_zg_poll_recover_param();
}

/**
 * @brief general message receive callback
 *
 * @param msg
 * @return TAL_MSG_RET_E
 */
TAL_MSG_RET_E tal_zcl_general_msg_recv_callback(TAL_ZCL_MSG_T *msg)
{
  // TAL_PR_TRACE("app gen msg cb: cluster 0x%02x, cmd %d\r\n", msg->cluster, msg->command);

  return ZCL_MSG_RET_SUCCESS;
}

/**
 * @brief post-write attribute callback
 *
 * @param[in] ep_id:      endpoint id
 * @param[in] cluster_id: cluster id
 * @param[in] attr_rec:   point to attribute record
 * @return write status
 */
TAL_WRITE_RET_E tal_zg_post_write_attribute_callback(UINT8_T ep_id,
                                                     UINT16_T cluster_id,
                                                     TAL_ATTR_REC_T *attr_rec)
{
  if (ONOFF_1_ENDPOINT == ep_id) {
      switch (cluster_id) {
          case CLUSTER_ON_OFF_CLUSTER_ID: {
              if (ATTR_ON_OFF_ATTRIBUTE_ID == attr_rec->attr_id) {
              }
              break;
          }
          default: {
              break;
          }
      }
  }
  if (ONOFF_2_ENDPOINT == ep_id) {
      switch (cluster_id) {
          case CLUSTER_ON_OFF_CLUSTER_ID: {
              if (ATTR_ON_OFF_ATTRIBUTE_ID == attr_rec->attr_id) {
              }
              break;
          }
          default: {
              break;
          }
      }
  }
  if (ONOFF_3_ENDPOINT == ep_id) {
    switch (cluster_id) {
        case CLUSTER_ON_OFF_CLUSTER_ID: {
            if (ATTR_ON_OFF_ATTRIBUTE_ID == attr_rec->attr_id) {
            }
            break;
        }
        default: {
            break;
        }
    }
}
  if (ONOFF_4_ENDPOINT == ep_id) {
  switch (cluster_id) {
      case CLUSTER_ON_OFF_CLUSTER_ID: {
          if (ATTR_ON_OFF_ATTRIBUTE_ID == attr_rec->attr_id) {
          }
          break;
      }
      default: {
          break;
      }
  }
}
  return WRITE_RET_SUCCESS;
}


/**
 * @brief when receive the onoff command, deal with it
 *
 * @param[in] ep_id
 * @param[in] cmd
 * @param[in] payload
 * @param[in] payload_len
 * @param[in] cmd_type
 *
 * @return none
 */
STATIC VOID_T app_onoff_cluster_cmd_handler(UINT8_T ep_id, UCHAR_T cmd, UINT8_T *payload, UINT8_T payload_len, ZIGBEE_CMD_E cmd_type)
{
  TAL_PR_TRACE("ep_id: %d,cmd: %d", ep_id, cmd);
    switch (ep_id)
    {
    case ONOFF_1_ENDPOINT:
    case ONOFF_2_ENDPOINT:
    case ONOFF_3_ENDPOINT:
    case ONOFF_4_ENDPOINT:
      app_onoff_cluster_write_report(ep_id, cmd);

      if(cmd == 1)
        rel_on(ep_id - 1, REPORT_DISABLE);
      else if(cmd == 0)
        rel_off(ep_id - 1, REPORT_DISABLE);
      break;

    default:
      break;
    }
}


/**
 * @brief specific message receive callback
 *
 * @param msg
 * @return TAL_MSG_RET_E
 */
TAL_MSG_RET_E tal_zcl_specific_msg_recv_callback(TAL_ZCL_MSG_T *msg)
{
  TAL_PR_TRACE("app spec msg cb: cluster 0x%02x, cmd 0x%02x leg %02x \r\n", msg->cluster, msg->command, msg->length);
  // print_zcl_msg_info(msg);
  ZIGBEE_CMD_E app_cmd_type = ZIGBEE_CMD_SINGLE;
  if (msg->mode == ZG_UNICAST_MODE)
  {
    app_cmd_type = ZIGBEE_CMD_SINGLE;
    TAL_PR_TRACE("receive single message");
  }
  else
  {
    app_cmd_type = ZIGBEE_CMD_GROUP;
    TAL_PR_TRACE("receive group message");
  }
  TAL_PR_TRACE("app command type %d", app_cmd_type);

  switch (msg->cluster)
  {
  case CLUSTER_ON_OFF_CLUSTER_ID:
  {
    app_onoff_cluster_cmd_handler(msg->dst_ep, msg->command, msg->payload, msg->length, app_cmd_type);
    // __report_user_onoff(msg->dst_ep, msg->length, &(msg->payload[0]), msg->command);
    break;
  }
  default:
  {
    break;
  }
  }

  //   switch (msg->cluster)
  //   {
  // #if IAS_ZONE_SUPPORT
  //   case CLUSTER_IAS_ZONE_CLUSTER_ID:
  //   {
  //     ias_zone_cluster_server_command_handler(msg->command, msg->payload, msg->length, app_cmd_type);
  //     break;
  //   }
  // #endif
  //   default:
  //     break;
  //   }

  return ZCL_MSG_RET_SUCCESS;
}

/**
 * @brief pre-save scene callback
 *
 * @param ep_id
 * @param scene_id
 * @param group_id
 * @return VOID_T
 */
VOID_T tal_zg_scene_pre_save_callback(UINT8_T ep_id, UINT8_T scene_id, UINT16_T group_id)
{
  // TAL_PR_TRACE("scene pre save: ep %d, sce %d, gp 0x%02x\r\n", ep_id, scene_id, group_id);
}

/**
 * @brief save scene callback(add scene and store scene)
 *
 * @param ep_id
 * @param scene_id
 * @param group_id
 * @param data
 * @return VOID_T
 */
VOID_T tal_zg_scene_save_callback(UINT8_T ep_id, UINT8_T scene_id, UINT16_T group_id, TAL_SCENE_DATA_T *data)
{
  // TAL_PR_TRACE("scene save: ep %d, sce %d, gp 0x%02x, type %d\r\n", ep_id, scene_id, group_id, data->type);
}
/**
 * @brief recall scene callback
 *
 * @param[in]   ep_id:     endpoint id
 * @param[in]   scene_id:  scene id
 * @param[in]   group_id:  group id
 * @param[in]   time100ms: scene transition time(bat:100ms)
 * @param[in]   data:      point to scene data
 * @return  VOID_T
 */
VOID_T tal_zg_scene_recall_callback(UINT8_T ep_id, UINT8_T scene_id, UINT16_T group_id, UINT_T time100ms, TAL_SCENE_DATA_T *data)
{
  TAL_PR_TRACE("scene recall: ep %d, sce %d, gp 0x%02x, type %d\r\n", ep_id, scene_id, group_id, data->type);
}

/**
 * @brief add group callback
 *
 * @param[in]   ep_id:    endpoint id
 * @param[in]   group_id: group id
 * @return  VOID_T
 */
VOID_T tal_zg_add_group_callback(UINT8_T ep_id, UINT16_T group_id)
{
  TAL_PR_TRACE("ep_id=%d, group_id=0x%04x", ep_id, group_id);
}

/**
 * @brief view group callback
 *
 * @param[in]   ep_id:    endpoint id
 * @param[in]   group_id: group id
 * @return  VOID_T
 */
VOID_T tal_zg_view_group_callback(UINT8_T ep_id, UINT16_T group_id)
{
  TAL_PR_TRACE("ep_id=%d, group_id=0x%04x", ep_id, group_id);
}

/**
 * @brief remove group callback
 *
 * @param[in]   ep_id:    endpoint id
 * @param[in]   group_id: group id
 * @return  VOID_T
 */
VOID_T tal_zg_remove_group_callback(UINT8_T ep_id, UINT16_T group_id)
{
  TAL_PR_TRACE("ep_id=%d, group_id=0x%04x", ep_id, group_id);
}

/**
 * @brief zigbee network network change callback(user can rewrite this API)
 *
 * @param[in]   status: network status
 * @return VOID_T
 */
VOID_T tal_zg_nwk_status_changed_callback(TAL_ZG_NWK_STATUS_E status)
{
  switch (status)
  {
  case TAL_ZG_NWK_POWER_ON_LEAVE:
  {
    TAL_PR_TRACE("power_on_leave---\r\n");
    break;
  }
  case TAL_ZG_NWK_POWER_ON_ONLINE:
  {
    TAL_PR_TRACE("power_on_online---\r\n");
    // tal_sw_timer_start(etimer_network_up_delay_event_id, 5000, TAL_TIMER_ONCE);
    break;
  }
  case TAL_ZG_NWK_JOIN_START:
  {
    TAL_PR_TRACE("nwk_join_start---\r\n");
    TAL_PR_TRACE("----------------------------------------------------------------------------\r\n");
#if APP_LED_SUPPORT
    // dev_start_join_indicate();
#endif
    device_status.led |= LED_STATUS_ZIGBEE_RESET;
    tal_sw_timer_start(etimer_led_blink_event_id, 0, TAL_TIMER_ONCE);
    break;
  }
  case TAL_ZG_NWK_JOIN_OK:
  {
    TAL_PR_TRACE("nwk_join_ok---\r\n");
    device_status.led &= ~LED_STATUS_ZIGBEE_RESET;
    set_led_status(0, LED_OFF);
    tal_sw_timer_start(zigbee_update_timer_id, 1500, TAL_TIMER_ONCE);
#if APP_LED_SUPPORT
    // dev_join_success_indicate();
#endif
  tal_sw_timer_start(etimer_network_up_delay_event_id, 1500, TAL_TIMER_ONCE);

    // app_battery_start();
    break;
  }
  case TAL_ZG_NWK_REJOIN_OK:
  {
    TAL_PR_TRACE("nwk_rejoin_ok---\r\n");
    device_status.led &= ~LED_STATUS_ZIGBEE_RESET;
    set_led_status(0, LED_OFF);
    tal_sw_timer_start(etimer_network_up_delay_event_id, 1500, TAL_TIMER_ONCE);
    tal_sw_timer_start(zigbee_update_timer_id, 1500, TAL_TIMER_ONCE);

        // 
    // app_battery_start();
    break;
  }
  case TAL_ZG_NWK_JOIN_TIMEOUT:
  {
    TAL_PR_TRACE("nwk_join_timeout---\r\n");
    device_status.led &= ~LED_STATUS_ZIGBEE_RESET;
    set_led_status(0, LED_OFF);
    break;
  }
  case TAL_ZG_NWK_LOST:
  {
    TAL_PR_TRACE("nwk_lost---\r\n");
    break;
  }
  case TAL_ZG_NWK_REMOTE_LEAVE:
  {
    TAL_PR_TRACE("nwk_remote_leave---\r\n");
    tal_zg_join_start(ZIGBEE_JOIN_TIMEOUT_MS);
    TAL_PR_TRACE("zigbee join start %d.\r\n", ZIGBEE_JOIN_TIMEOUT_MS);
    break;
  }
  case TAL_ZG_NWK_LOCAL_LEAVE:
  {
    TAL_PR_TRACE("nwk_local_leave---\r\n");
    break;
  }
  case TAL_ZG_NWK_MF_TEST_LEAVE:
  {
    TAL_PR_TRACE("nwk_mf_test_leave---\r\n");
    break;
  }
  default:
  {
    break;
  }
  }
}
/**
 * @brief reset factory default callback
 *
 * @param[in]   type: reset factory type
 * @return  VOID_T
 */
VOID_T tal_zg_reset_factory_default_callback(TAL_RESET_TYPE_T type)
{
  TAL_PR_TRACE("receive reset to factory default cmd %d\r\n", type);
}

/**
 * @note uart init
 * @param [in] none
 * @return: OPERATE_RET
 */
STATIC VOID_T app_debug_uart_init(VOID_T)
{
  TAL_UART_CFG_T cfg;
  tal_system_memset(&cfg, 0, SIZEOF(TAL_UART_CFG_T));

  cfg.rx_buffer_size = 128;
  cfg.open_mode = 0;
  cfg.base_cfg.baudrate = 115200;
  cfg.base_cfg.parity = TUYA_UART_PARITY_TYPE_NONE;
  cfg.base_cfg.databits = TUYA_UART_DATA_LEN_8BIT;
  cfg.base_cfg.stopbits = TUYA_UART_STOP_LEN_1BIT;
  cfg.base_cfg.flowctrl = TUYA_UART_FLOWCTRL_NONE;
  tal_uart_init(USER_UART, &cfg);
}
VOID_T tal_beacon_mf_test_callback(VOID_T)
{
  TAL_PR_TRACE("enter beacon test\r\n");
}

VOID_T tal_mf_test_pre_start_callback(VOID_T *args)
{
  TAL_PR_TRACE("enter dongle-beacon start\r\n");
}

VOID_T tal_mf_test_end_callback(UINT8_T *data)
{
  TAL_PR_TRACE("enter dongle-beacon end, value %d\r\n", *data);
}

#ifdef MCU_CORE_8258
#include "tkl_platform_types.h"

BOOL_T app_print_get_cfg(UINT8_T *print_type, UINT8_T *disable_irq, GPIO_PORT_PIN_T *gpio)
{
  gpio->port = PORT_B;
  gpio->pin = PIN_7;
  *print_type = 0;
  *disable_irq = 1;
#if UART_PRINTF_MODE
  return 1;
#else
  return 0;
#endif
}

#if END_DEVICE
/***********************定义该函数表示gpio休眠不保持，需要自己把控休眠节奏********************************/
BOOL_T tkl_gpio_output_use_wakeup_mode(TUYA_GPIO_NUM_E pin_id)
{
  // TAL_PR_TRACE("tkl_gpio_output_use_wakeup_mode FALSE");
  return FALSE;
  // return TRUE;
}
#endif

/***********************定义该函数用于重新分配管脚中断源，一般与 gpio_int_fast_handle 配合使用用于处理快速中断输入********************************/
BOOL_T tkl_reallocate_gpio_interrupt_source(TUYA_GPIO_NUM_E pin, UINT8_T before_mode, UINT8_T *after_mode)
{
  return FALSE;
}

#endif